/**
    author: liaowenbing< sw@uninew.com / liaowb1234@126.com>
    time:   2013-02-21
    company: www.uninew.com
*/

#include "car_server.h"

CarHardwareBase::CarHardwareBase(car_hardware_param_t* param,ProtocolInterface* pro)
{
	int ret = init(param,pro);
	if(ret > 0){
		mState =1 ;
		start();
	}
}

CarHardwareBase::~CarHardwareBase
{
	if(mState>0){
		this.exit();
	}
}

//============================================================================
int CarHardwareBase::init(car_hardware_param_t* param,ProtocolInterface* pro)
{
    if(param == NULL || pro == NULL){
        return -1;
    }

    mProto = pro;
    if(HardwareOpen(param) < 0){
        LOGOUT_E("HardwareOpen error return \n");
        mProto = NULL;
        return -1;
    }

    if(BufferInit()<0){
    	HardwareClose();
    	mProto = NULL;
      return -1;
    }

    iMaxPacketLength = mProto->GetPacketMaxLen();
    iMinPacketLength = mProto->GetPacketMinLen();

    iHWNewReadedCount = 0;
    mHWThread = NULL;
		SetThreadState(CN_CAR_THREAD_ST_NONO);
    LOGOUT_D("init finish");
    return 1;
}

int CarHardwareBase::SetThreadState(int st)
{
	iThreadState = st;
}

int CarHardwareBase::GetThreadState()
{
	return iThreadState;
}

int CarHardwareBase::IsThreadExit()
{
	return (iThreadState == CN_CAR_THREAD_ST_WAIT_EXIT);
}

int CarHardwareBase::MemoryAlloc(char **out,int sizeout,char **in,int sizein)
{
    char* ptr = (char *)malloc(sizeout);
    if(ptr == NULL){
        return -1;
    }
    *out = ptr;
    ptr = (char *)malloc(sizein);
    if(ptr == NULL){
        free(*out);
        return -1;
    }
    *in = ptr;
    return 0;
}

void CarHardwareBase::MemoryFree(char *out,char* in)
{
    if(out!=NULL){
        free(out);
    }
    if(in != NULL){
        free(in);
    }
}

int CarHardwareBase::BufferInit()
{
		char **out,**in;
    int outlen = 4 * mProto->GetPacketMaxLen();
    int inlen = 4 * mProto->GetPacketMaxLen();

    if(MemoryAlloc(out,outlen,in,inlen) < 0){
        return -1;
    }

    mOutBuf.buffer = *out;
    mInBuf.buffer = *in;
    mOutBuf.buff_len = outlen;
    mInBuf.buff_len = inlen;

    mOutBuf.data_begin = 1;
    mOutBuf.data_len = 0;

    mInBuf.data_begin = 0;
    mInBuf.data_len = 0;
}

int CarHardwareBase::Bufferfree()
{
	int ret = MemoryFree(mOutBuf.buffer,mInBuf.buffer);
	mOutBuf.buffer = NULL;
	mOutBuf.buff_len = 0;
	mOutBuf.data_begin = 0;
	mOutBuf.data_len = 0;
	mInBuf.buffer = NULL;
	mInBuf.buff_len = 0;
	mInBuf.data_begin = 0;
	mInBuf.data_len = 0;
	return ret;
}

int CarHardwareBase::SendAppPacketToHW()
{
    int ret;
    mInBuf.data_len = 0;
    while(1){
        ret = mProto->GetAppDatas(mInBuf.buffer + mInBuf.data_len, mInBuf.buff_len - mInBuf.data_len);
        if(ret < 1){
            if( mInBuf.data_len < 1){
                break;
            }else{
                ret = 0;
            }
        }

        mInBuf.data_len += ret;
        send_count = HardwareSend(mInBuf.buffer,mInBuf.data_len);
        if(send_count < 1){
            LOGOUT_E("Error:Why hardware send data return < 1 !!!???\n");
            return -1;
        }

        mInBuf.data_len -= send_count;
        if(mInBuf.data_len > 0){
            memcpy(mInBuf.buffer,mInBuf.buffer+send_count,mInBuf.data_len);
            LOGOUT_D("Liaowb warning: hardware connot send datas at one time(nend send=%d,sended=%d!!!\n",mInBuf.data_len,send_count);
        }
    }
    return 0;
}

int CarHardwareBase::ReadHWDatasToApp()
{
    int count;
    int free_to_end,old_begin;

    if(iHWNewReadedCount < 1){
        return 0;
    }

    //First to do is Check Buffer data is a packet data
    count = mProto->ProcessPacketDatas(mOutBuf.buffer + mOutBuf.data_begin, mOutBuf.data_len);
    if(count > 0){
        mOutBuf.data_len -= count;
        if(mOutBuf.data_len > 0){
            mOutBuf.data_begin = mOutBuf.data_begin + count;
        }else{
            mOutBuf.data_begin = 1;
        }
    }

    free_to_end = mOutBuf.buff_len - mOutBuf.data_begin - mOutBuf.data_len;
    if( (mOutBuf.data_len > 0) && (mOutBuf.data_len + free_to_end) < iMaxPacketLength ) ){
        old_begin = mOutBuf.data_begin;
        mOutBuf.data_begin = 1;
        memcpy(mOutBuf.buffer + mOutBuf.data_begin,mOutBuf.buffer+old_begin,mOutBuf.data_len);

        free_to_end = mOutBuf.buff_len - mOutBuf.data_begin - mOutBuf.data_len;
    }
    iHWNewReadedCount = 0;

    count = HardwareRead(mOutBuf.buffer + mOutBuf.data_begin + mOutBuf.data_len, free_to_end,iMaxReadHWMsTime);
    if(count > 0){
        mOutBuf.data_len += count;
        iHWNewReadedCount = count;
    }else if(count < 0){
        LOGOUT_E("Error:Why hardware read datas return < 0 !!!???\n");
    }
    return count;
}

void CarHardwareBase::CarHWThreadLoop(void*)
{
    int ret;
    while(!IsThreadExit()){
        ret = SendAppPacketToHW();
        ret = ReadHWDatasToApp();
    }
    SetThreadState(CN_CAR_THREAD_ST_NONO);
    mHWThread = NULL;
    LOGOUT_D("Car thread loop exit\n:");
}

int CarHardwareBase::start()
{
    if(mProto == NULL){
        return -1;
    }

    if(mHWThread != NULL){
			return 0; //had started befor
		}

		if(pthread_create(&mHWThread,NULL,CarHWThreadLoop,NULL)!=0){
				LOGOUT_E("create write thread error!\n");
				return -1;
		}else{
				SetThreadState(CN_CAR_THREAD_ST_LOOP);
				pthread_detach(mHWThread);
				mProto->start();
		}
		LOGOUT_D("CarBase start\n:");
		return 1;
}

void CarHardwareBase::stop()
{
	int count = 100;
	if(mHWThread && (GetThreadState() == CN_CAR_THREAD_ST_LOOP)){
		SetThreadState(CN_CAR_THREAD_ST_WAIT_EXIT);
		while(mHWThread && --count){
			sleep(1);
		}
		mProto->stop();
		LOGOUT_D("CarBase stop\n:");
	}
}

void CarHardwareBase::exit()
{
	stop();
	HardwareClose();
	Bufferfree();
	LOGOUT_D("CarBase exit\n:");
}

int CarHardwareBase::setpara(car_hardware_param_t* para)
{
	return HardwareSetParam(para);
}

int getpara(car_hardware_param_t* para)
{
	return HardwareGetParam(para);
}
